package com.freak.kotlinfitnessserver.factory.notify

import com.freak.kotlinfitnessserver.constant.ByteConstant
import com.freak.kotlinfitnessserver.data.FitnessConfigData
import com.freak.kotlinfitnessserver.factory.INotifyFactory
import com.freak.kotlinfitnessserver.factory.notify.data.BlueRealTimeData
import com.freak.kotlinfitnessserver.factory.notify.data.FlagEntity
import com.freak.kotlinfitnessserver.util.ByteUtil
import com.freak.kotlinfitnessserver.util.LogUtil

class RowerNotifyFactory : INotifyFactory {
    companion object {
        const val TAG: String = "RowerNotifyFactory"
    }

    private var blueRealTimeData: BlueRealTimeData? = null

    override fun getNotifyByteArray(
        sportStatus: Int,
        fitnessConfigData: FitnessConfigData?
    ): ByteArray {
        return ByteArray(0)
    }

    override fun getNotifyByteArrayList(
        sportStatus: Int,
        fitnessConfigData: FitnessConfigData?
    ): List<ByteArray> {
        //  数组长度会超出20，超出部分需要分包，分包需要对应的flag，需要返回byte数组列表的新式
        // 根据Fitness Machine Feature填充支持的数据
        fitnessConfigData ?: let {
            LogUtil.i(TreadmillNotifyFactory.TAG, "fitnessConfigData is null")
            return ArrayList()
        }
        if (blueRealTimeData == null) {
            LogUtil.i(TreadmillNotifyFactory.TAG, "init blueRealTimeData")
            blueRealTimeData = BlueRealTimeData()
        }
        configBlueRealTimeDataWithFlag(blueRealTimeData!!, fitnessConfigData)
        val flagEntity = initByteArrayWithBlueRealTimeData(blueRealTimeData!!)
        val list = configByteArrayListWithFlag(
            flagEntity.dataLength,
            flagEntity.flag,
            blueRealTimeData!!
        )
        return list
    }


    private fun getFlagList(list: List<FlagEntity>, flag: Int): List<FlagEntity> {
        val flagList = ArrayList<FlagEntity>()
        if (list.isNotEmpty()) {
            flagList.addAll(list)
        }
        var dataLength = 2
        var resultFlag = ByteConstant.BYTE_0X00
        // Stroke Rate and Stroke Count
        if (flag and ByteConstant.BYTE_0X01 == 0) {
            // StrokeRate
            dataLength += 1
            // StrokeCount
            dataLength += 2
        } else {
            resultFlag = ByteConstant.BYTE_0X01
        }
        // AverageStrokeRate
        if (flag and ByteConstant.BYTE_0X02 != 0) {
            resultFlag = resultFlag xor ByteConstant.BYTE_0X02
            dataLength += 1
        }
        // TotalDistance
        if (flag and ByteConstant.BYTE_0X04 != 0) {
            resultFlag = resultFlag xor ByteConstant.BYTE_0X04
            dataLength += 3
        }
        // InstantaneousPace
        if (flag and ByteConstant.BYTE_0X08 != 0) {
            resultFlag = resultFlag xor ByteConstant.BYTE_0X08
            dataLength += 2
        }
        // AveragePace
        if (flag and ByteConstant.BYTE_0X10 != 0) {
            resultFlag = resultFlag xor ByteConstant.BYTE_0X10
            dataLength += 2
        }
        // InstantaneousPower
        if (flag and ByteConstant.BYTE_0X20 != 0) {
            resultFlag = resultFlag xor ByteConstant.BYTE_0X20
            dataLength += 2
        }
        // AveragePower
        if (flag and ByteConstant.BYTE_0X40 != 0) {
            resultFlag = resultFlag xor ByteConstant.BYTE_0X40
            dataLength += 2
        }
        // ResistanceLevel
        if (flag and ByteConstant.BYTE_0X80 != 0) {
            resultFlag = resultFlag xor ByteConstant.BYTE_0X80
            dataLength += 2
        }
        // Expended Energy
        if (flag and ByteConstant.BYTE_0x100 != 0) {
            if (!checkLength(dataLength, 6)) {
                return getFlagList(flag, resultFlag, flagList, dataLength)
            }
            resultFlag = resultFlag xor ByteConstant.BYTE_0x100
            // Total Energy
            dataLength += 2
            // Energy per Hour
            dataLength += 2
            // Energy per Minute
            dataLength += 2
        }
        // Heart Rate
        if (flag and ByteConstant.BYTE_0x200 != 0) {
            if (!checkLength(dataLength, 1)) {
                return getFlagList(flag, resultFlag, flagList, dataLength)
            }
            resultFlag = resultFlag xor ByteConstant.BYTE_0x200
            dataLength += 1
        }
        // MetabolicEquivalent
        if (flag and ByteConstant.BYTE_0x400 != 0) {
            if (!checkLength(dataLength, 1)) {
                return getFlagList(flag, resultFlag, flagList, dataLength)
            }
            resultFlag = resultFlag xor ByteConstant.BYTE_0x400
            dataLength += 1
        }
        // ElapsedTime
        if (flag and ByteConstant.BYTE_0x800 != 0) {
            if (!checkLength(dataLength, 2)) {
                return getFlagList(flag, resultFlag, flagList, dataLength)
            }
            resultFlag = resultFlag xor ByteConstant.BYTE_0x800
            dataLength += 2
        }
        // RemainingTime
        if (flag and ByteConstant.BYTE_0x1000 != 0) {
            if (!checkLength(dataLength, 2)) {
                return getFlagList(flag, resultFlag, flagList, dataLength)
            }
            resultFlag = resultFlag xor ByteConstant.BYTE_0x1000
            dataLength += 2
        }
        val flagEntity = FlagEntity()
        flagEntity.flag = resultFlag
        flagEntity.dataLength = dataLength
        flagList.add(flagEntity)
        return flagList
    }

    private fun checkLength(dataLength: Int, paraLength: Int): Boolean {
        return dataLength + paraLength <= 20
    }

    private fun getFlagList(
        flag: Int,
        resultFlag: Int,
        flagList: ArrayList<FlagEntity>,
        dataLength: Int
    ): List<FlagEntity> {
        // 获取剩余数据的flag
        // 注意：flag的第一位（bit0）存在数据时，标志为是0，所以需要特别处理一下
        val residualDataFlag = if (flag and ByteConstant.BYTE_0X01 == 0) {
            flag xor resultFlag xor ByteConstant.BYTE_0X01
        } else {
            flag xor resultFlag xor ByteConstant.BYTE_0X00
        }
        val flagEntity = FlagEntity()
        flagEntity.flag = resultFlag
        flagEntity.dataLength = dataLength
        flagList.add(flagEntity)
        return getFlagList(flagList, residualDataFlag)
    }

    private fun configByteArrayListWithFlag(
        dataLength: Int,
        flag: Int,
        blueRealTimeData: BlueRealTimeData
    ): List<ByteArray> {
        LogUtil.i(
            TreadmillNotifyFactory.TAG,
            "configByteArrayListWithFlag flag = $flag dataLength = $dataLength"
        )
        val resultList = ArrayList<ByteArray>()
        // 需要分包
        if (dataLength > 20) {
            val flagList = getFlagList(ArrayList(), flag)
            for (flagEntity in flagList) {
                val byteArray = configByteArrayWithFlag(
                    flagEntity.dataLength,
                    flagEntity.flag,
                    blueRealTimeData
                )
                resultList.add(byteArray)
            }
            return resultList
        }
        // 不需要分包
        val byteArray = configByteArrayWithFlag(
            dataLength,
            flag,
            blueRealTimeData
        )
        resultList.add(byteArray)
        return resultList
    }

    private fun configByteArrayWithFlag(
        dataLength: Int,
        flag: Int,
        blueRealTimeData: BlueRealTimeData
    ): ByteArray {
        LogUtil.i(TAG, "configByteArrayWithFlag flag = $flag dataLength = $dataLength")
        val byteArray = ByteArray(dataLength)
        var offset = 0
        ByteUtil.intToTwoByteArray(byteArray, flag, offset)
        LogUtil.i(TAG, "flag = $flag")
        offset += 2
        // Stroke Rate and Stroke Count
        if (flag and ByteConstant.BYTE_0X01 == 0) {
            // StrokeRate
            ByteUtil.intToOneByteArray(byteArray, blueRealTimeData.mStrokeRate, offset)
            LogUtil.i(TAG, "strokeRate = ${blueRealTimeData.mStrokeRate}")
            offset += 1
            // StrokeCount
            ByteUtil.intToTwoByteArray(byteArray, blueRealTimeData.mStrokeCount, offset)
            LogUtil.i(TAG, "strokeCount = ${blueRealTimeData.mStrokeCount}")
            offset += 2
        }
        // AverageStrokeRate
        if (flag and ByteConstant.BYTE_0X02 != 0) {
            ByteUtil.intToOneByteArray(byteArray, blueRealTimeData.mAverageStrokeRate, offset)
            LogUtil.i(TAG, "averageStrokeRate = ${blueRealTimeData.mAverageStrokeRate}")
            offset += 1
        }
        // TotalDistance
        if (flag and ByteConstant.BYTE_0X04 != 0) {
            ByteUtil.intToThreeByteArray(byteArray, blueRealTimeData.mTotalDistance, offset)
            LogUtil.i(TAG, "totalDistance = ${blueRealTimeData.mTotalDistance}")
            offset += 3
        }
        // InstantaneousPace
        if (flag and ByteConstant.BYTE_0X08 != 0) {
            ByteUtil.intToTwoByteArray(byteArray, blueRealTimeData.mInstantaneousPace, offset)
            LogUtil.i(TAG, "instantaneousPace = ${blueRealTimeData.mInstantaneousPace}")
            offset += 2
        }
        // AveragePace
        if (flag and ByteConstant.BYTE_0X10 != 0) {
            ByteUtil.intToTwoByteArray(byteArray, blueRealTimeData.mAveragePace, offset)
            LogUtil.i(TAG, "averagePace = ${blueRealTimeData.mAveragePace}")
            offset += 2
        }
        // InstantaneousPower
        if (flag and ByteConstant.BYTE_0X20 != 0) {
            ByteUtil.intToTwoByteArray(byteArray, blueRealTimeData.mInstantaneousPower, offset)
            LogUtil.i(TAG, "instantaneousPower = ${blueRealTimeData.mInstantaneousPower}")
            offset += 2
        }
        // AveragePower
        if (flag and ByteConstant.BYTE_0X40 != 0) {
            ByteUtil.intToTwoByteArray(byteArray, blueRealTimeData.mAveragePower, offset)
            LogUtil.i(TAG, "averagePower = ${blueRealTimeData.mAveragePower}")
            offset += 2
        }
        // ResistanceLevel
        if (flag and ByteConstant.BYTE_0X80 != 0) {
            ByteUtil.intToTwoByteArray(byteArray, blueRealTimeData.mResistanceLevel, offset)
            LogUtil.i(TAG, "resistanceLevel = ${blueRealTimeData.mResistanceLevel}")
            offset += 2
        }
        // Expended Energy
        if (flag and ByteConstant.BYTE_0x100 != 0) {
            // Total Energy
            ByteUtil.intToTwoByteArray(byteArray, blueRealTimeData.mTotalEnergy, offset)
            LogUtil.i(TAG, "totalEnergy = ${blueRealTimeData.mTotalEnergy}")
            offset += 2
            // Energy per Hour
            ByteUtil.intToTwoByteArray(byteArray, blueRealTimeData.mEnergyPerHour, offset)
            LogUtil.i(TAG, "energyPerHour = ${blueRealTimeData.mEnergyPerHour}")
            offset += 2
            // Energy per Minute
            ByteUtil.intToTwoByteArray(byteArray, blueRealTimeData.mEnergyPerMinute, offset)
            LogUtil.i(TAG, "energyPerMinute = ${blueRealTimeData.mEnergyPerMinute}")
            offset += 2
        }
        // Heart Rate
        if (flag and ByteConstant.BYTE_0x200 != 0) {
            ByteUtil.intToOneByteArray(byteArray, blueRealTimeData.mHeartRate, offset)
            LogUtil.i(TAG, "heartRate = ${blueRealTimeData.mHeartRate}")
            offset += 1
        }
        // MetabolicEquivalent
        if (flag and ByteConstant.BYTE_0x400 != 0) {
            ByteUtil.intToOneByteArray(byteArray, blueRealTimeData.mMetabolicEquivalent, offset)
            LogUtil.i(TAG, "metabolicEquivalent = ${blueRealTimeData.mMetabolicEquivalent}")
            offset += 1
        }
        // ElapsedTime
        if (flag and ByteConstant.BYTE_0x800 != 0) {
            ByteUtil.intToTwoByteArray(byteArray, blueRealTimeData.mElapsedTime, offset)
            LogUtil.i(TAG, "elapsedTime = ${blueRealTimeData.mElapsedTime}")
            offset += 2
        }
        // RemainingTime
        if (flag and ByteConstant.BYTE_0x1000 != 0) {
            ByteUtil.intToTwoByteArray(byteArray, blueRealTimeData.mRemainingTime, offset)
            LogUtil.i(TAG, "remainingTime = ${blueRealTimeData.mRemainingTime}")
            offset += 2
        }
        return byteArray
    }

    private fun initByteArrayWithBlueRealTimeData(blueRealTimeData: BlueRealTimeData): FlagEntity {
        // 初始长度是flag的长度，flag的长度为2
        var byteArrayLength = 2
        var flag = ByteConstant.BYTE_0X00
        if (blueRealTimeData.mStrokeRate > 0
            && blueRealTimeData.mStrokeCount > 0
        ) {
            ByteConstant.BYTE_0X00
            byteArrayLength += 1
            byteArrayLength += 2
        } else {
            ByteConstant.BYTE_0X01
        }

        if (blueRealTimeData.mAverageStrokeRate > 0) {
            flag = flag xor ByteConstant.BYTE_0X02
            byteArrayLength += 1
        }
        if (blueRealTimeData.mTotalDistance > 0) {
            flag = flag xor ByteConstant.BYTE_0X04
            byteArrayLength += 3
        }
        if (blueRealTimeData.mInstantaneousPace > 0) {
            flag = flag xor ByteConstant.BYTE_0X08
            byteArrayLength += 2
        }
        if (blueRealTimeData.mAveragePace > 0) {
            flag = flag xor ByteConstant.BYTE_0X10
            byteArrayLength += 2
        }
        if (blueRealTimeData.mInstantaneousPower > 0) {
            flag = flag xor ByteConstant.BYTE_0X20
            byteArrayLength += 2
        }
        if (blueRealTimeData.mAveragePower > 0) {
            flag = flag xor ByteConstant.BYTE_0X40
            byteArrayLength += 2
        }
        if (blueRealTimeData.mResistanceLevel > 0) {
            flag = flag xor ByteConstant.BYTE_0X80
            byteArrayLength += 2
        }
        if (blueRealTimeData.mTotalEnergy > 0
            && blueRealTimeData.mEnergyPerHour > 0
            && blueRealTimeData.mEnergyPerMinute > 0
        ) {
            flag = flag xor ByteConstant.BYTE_0x100
            byteArrayLength += 2
            byteArrayLength += 2
            byteArrayLength += 2
        }
        if (blueRealTimeData.mHeartRate > 0) {
            flag = flag xor ByteConstant.BYTE_0x200
            byteArrayLength += 1
        }
        if (blueRealTimeData.mMetabolicEquivalent > 0) {
            flag = flag xor ByteConstant.BYTE_0x400
            byteArrayLength += 1
        }
        if (blueRealTimeData.mElapsedTime > 0) {
            flag = flag xor ByteConstant.BYTE_0x800
            byteArrayLength += 2
        }
        if (blueRealTimeData.mRemainingTime > 0) {
            flag = flag xor ByteConstant.BYTE_0x1000
            byteArrayLength += 2
        }
        val flagEntity = FlagEntity()
        flagEntity.flag = flag
        flagEntity.dataLength = byteArrayLength
        return flagEntity
    }

    private fun configBlueRealTimeDataWithFlag(
        blueRealTimeData: BlueRealTimeData,
        fitnessConfigData: FitnessConfigData
    ) {
        // 实时数据从bit0开始设置
        blueRealTimeData.mStrokeRate = 0
        blueRealTimeData.mStrokeCount = 0
        val flag = fitnessConfigData.fitnessMachineFeaturesFlag
        if (flag and ByteConstant.BYTE_0X02 != 0) {
            // Cadence Supported
            blueRealTimeData.mAverageStrokeRate = 0
        }
        if (flag and ByteConstant.BYTE_0X04 != 0) {
            // Total Distance Supported
            blueRealTimeData.mTotalDistance = 0
        }
        if (flag and ByteConstant.BYTE_0X20 != 0) {
            // Pace Supported
            blueRealTimeData.mInstantaneousPace = 0
            blueRealTimeData.mAveragePace = 0
        }
        if (flag and ByteConstant.BYTE_0X80 != 0) {
            // Resistance Level Supported
            blueRealTimeData.mResistanceLevel = 0
        }
        if (flag and ByteConstant.BYTE_0x200 != 0) {
            // Expended Energy Supported
            blueRealTimeData.mTotalEnergy = 0
            blueRealTimeData.mEnergyPerHour = 0
            blueRealTimeData.mEnergyPerMinute = 0
        }
        if (flag and ByteConstant.BYTE_0x400 != 0) {
            // Heart Rate Measurement Supported
            blueRealTimeData.mHeartRate = 0
        }
        if (flag and ByteConstant.BYTE_0x800 != 0) {
            // Metabolic Equivalent Supported
            blueRealTimeData.mMetabolicEquivalent = 0
        }
        if (flag and ByteConstant.BYTE_0x1000 != 0) {
            // Elapsed Time Supported
            blueRealTimeData.mElapsedTime = 0
        }
        if (flag and ByteConstant.BYTE_0x2000 != 0) {
            // Remaining Time Supported
            blueRealTimeData.mRemainingTime = 0
        }
        if (flag and ByteConstant.BYTE_0x4000 != 0) {
            // Power Measurement Supported
            blueRealTimeData.mInstantaneousPower = 0
            blueRealTimeData.mAveragePower = 0
        }
    }
}